<template>
  <div class="cus-upload" @click="handleClick">
    <slot></slot>
    <input @change="handleChange($event)" :multiple="multiple" ref="input" type="file" name="file" class="dn"/>
  </div>
</template>

<script>
import _ from 'lodash'
import CryptoJS from 'crypto-js'
import SparkMD5 from 'spark-md5'
// import { fileUpload } from '../api/api.js'
export default {
  name: 'CusUpload',
  data () {
    return {
      currentFile: {
        percentage: 0,
        loading: false,
        readPercent: 0,
        reading: false
      },
      defaultAttr: {
        fileName: 'fileName',
        fileSize: 'fileSize',
        fileType: 'fileType',
        imgUrl: 'imgUrl'
      }
    }
  },
  props: {
    attr: Object,
    limit: Number,
    fileList: Array, // 上传列表
    disabled: Boolean,
    multiple: Boolean,
    data: Number, // 自定义字段（上传完成原样返回）
    onSuccess: Function, // 上传成功 function(response, file, fileList, data) fileList 和 data 可选
    onError: Function, // 上传错误
    beforeUpload: Function, // 限制上传类型
    onExceed: Function, // 是否限制个数
    onProgress: Function, // 是否显示进度条
    onCompute: Function
  },
  methods: {
    handleClick () {
      if (!this.disabled) {
        this.$refs.input.value = null
        this.$refs.input.click()
      }
    },
    handleChange (ev) {
      const files = ev.target.files
      if (!files) return
      this.uploadFiles(files)
    },
    uploadFiles (files) {
      if (this.limit && this.fileList.length + files.length > this.limit) {
        return this.onExceed && this.onExceed(files, this.fileList)
      }

      let postFiles = Array.prototype.slice.call(files)
      if (!this.multiple) { postFiles = postFiles.slice(0, 1) }

      if (postFiles.length === 0) { return }

      postFiles.forEach((rawFile) => {
        // if (!this.beforeUpload) {
        //   return this.computeFile(rawFile, this.post)
        // }

        const before = !this.beforeUpload || this.beforeUpload(rawFile)
        console.log(before)
        if (before) {
          this.computeFile(rawFile, this.post)
        }
      })
    },

    // 计算文件MD5值和sha256
    computeFile (rawFile, callback) {
      let _this = this
      this.currentFile[this.defaultAttr['fileType']] = rawFile.type.split('/')[1].toUpperCase()
      this.currentFile[this.defaultAttr['fileName']] = rawFile.name
      this.currentFile[this.defaultAttr['fileSize']] = this.getfilesize(rawFile.size)
      this.currentFile[this.defaultAttr['imgUrl']] = rawFile.type.indexOf('image') !== -1 ? URL.createObjectURL(rawFile) : require('../assets/video.png')
      if (this.fileList) {
        let fileItem = _.cloneDeep(this.currentFile)
        this.fileList.push(fileItem)
      }

      // 声明必要的变量
      let fileReader = new FileReader()
      // 文件分割方法
      let blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice
      // 文件每块分割2M，计算分割详情
      let chunkSize = 2097152
      let chunks = Math.ceil(rawFile.size / chunkSize)
      let currentChunk = 0

      let spark = new SparkMD5.ArrayBuffer()
      // const digestMd5 = CryptoJS.algo.MD5.create()
      const digestSha256 = CryptoJS.algo.SHA256.create()

      // 每块文件读取完毕之后的处理
      fileReader.onload = function (e) {
        const buffer = e.target.result
        // 每块交由sparkMD5进行计算
        spark.append(buffer)
        currentChunk++

        const array = new Uint8Array(buffer)
        const content = CryptoJS.lib.WordArray.create(array)
        // digestMd5.update(content)
        digestSha256.update(content)

        // 如果文件处理完成计算MD5，如果还有分片继续处理
        if (currentChunk < chunks) {
          loadNext()
        } else {
          if (_this.fileList) {
            _this.fileList[_this.fileList.length - 1].reading = false
          }
          // let md5 = digestMd5.finalize().toString(CryptoJS.enc.Hex)
          let sha256 = digestSha256.finalize().toString(CryptoJS.enc.Hex)
          let md5 = spark.end()
          callback(rawFile, md5, sha256)
        }
      }
      fileReader.onerror = function () {
        console.warn('oops, something went wrong.')
      }

      function loadNext () {
        let start = currentChunk * chunkSize
        let end = start + chunkSize >= rawFile.size ? rawFile.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(rawFile, start, end))
        let progress = Math.ceil((currentChunk / chunks) * 100)

        if (_this.fileList) {
          _this.fileList[_this.fileList.length - 1].reading = true
          _this.fileList[_this.fileList.length - 1].readPercent = progress
        }
      }
      loadNext()
    },

    // 文件大小转换
    getfilesize (size) {
      if (!size) { return '' }

      var num = 1024.00 // byte

      if (size < num) { return size + 'B' }
      if (size < Math.pow(num, 2)) { return (size / num).toFixed(2) + 'K' } // kb
      if (size < Math.pow(num, 3)) { return (size / Math.pow(num, 2)).toFixed(2) + 'M' } // M
      if (size < Math.pow(num, 4)) { return (size / Math.pow(num, 3)).toFixed(2) + 'G' } // G
      return (size / Math.pow(num, 4)).toFixed(2) + 'T' // T
    },

    // 计算文件真实类型
    checkFileType (rawFile, callback) {
      let _this = this
      var fileReader = new FileReader()
      var blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice
      fileReader.onload = function (e) {
        const buffer = e.target.result
        var array = new Uint8Array(buffer)
        var hashType = ''
        for (var p in array) {
          const v = array[p]
          var tmp
          var num = v
          if (num < 0) {
            // 此处填坑，当byte因为符合位导致数值为负时候，需要对数据进行处理
            tmp = (255 + num + 1).toString(16)
          } else {
            tmp = num.toString(16)
          }
          if (tmp.length === 1) {
            tmp = '0' + tmp
          }
          hashType += tmp
        }
        _this.computeFile(rawFile, callback, hashType)
      }
      fileReader.readAsArrayBuffer(blobSlice.call(rawFile, 0, 10))
    },

    // 上传文件
    post (rawFile, MD5Hash, sha256) {
      this.onSuccess(null, rawFile, this.fileList)

      // let param = new FormData()
      // param.append('file', rawFile)
      // let params = {
      //   data: param,
      //   md5: MD5Hash,
      //   sha256: sha256,
      //   callback: this.postLoading
      // }

      // fileUpload(params).then(res => {
      //   if (this.fileList) {
      //     this.fileList[this.fileList.length - 1].loading = false
      //   }
      //   if (res.code !== 1) {
      //     if (this.fileList) {
      //       // this.fileList.splice(this.fileList.length - 1, 1)
      //     }
      //     this.onError(res, rawFile)
      //   } else {
      //     // this.fileList.splice(this.fileList.length - 1, 1)
      //     this.onSuccess(res, rawFile, this.fileList)
      //   }
      // })
    },

    postLoading (progress) {
      let loaded = progress.loaded
      let total = progress.total
      this.$nextTick(() => {
        let percent = parseFloat(loaded / total).toFixed(2)
        let percentage = Math.round(percent * 100)
        if (this.fileList) {
          this.fileList[this.fileList.length - 1].loading = false
          this.fileList[this.fileList.length - 1].percentage = percentage
        }
        if (this.onProgress) {
          this.onProgress(percentage)
        }
      })
    }
  },
  mounted () {
    if (this.attr) {
      for (const key in this.attr) {
        if (this.attr.hasOwnProperty(key)) {
          this.defaultAttr[key] = this.attr[key]
        }
      }
    }
  }
}
</script>
